﻿using System.Collections.Generic;
using UnityEngine;
using Unity.Entities;
using Unity.Jobs;

namespace Jinndev.ECS {

    /// <summary>
    /// 将Entity与UnityEngine.Component关联，原理是在Entity上增加一个DynamiceBuffer记录Component的instanceID
    /// </summary>
    public class ComponentInstanceSystem : JobComponentSystem {

        private Dictionary<int, Component> instances = new Dictionary<int, Component>();


        /// <summary>
        /// 关联到Entity，并返回com的instanceID
        /// </summary>
        public int AddComponent(Entity entity, Component com) {
            int id = com.GetInstanceID();
            instances.Add(id, com);

            DynamicBuffer<ComponentInstance> buffer = ECSUtil.GetOrAddBuffer<ComponentInstance>(EntityManager, entity);
            buffer.Add(new ComponentInstance { id = id });

            return id;
        }

        /// <summary>
        /// 通过instanceID获得关联的Component
        /// </summary>
        public Component GetComponent(int instanceID) {
            if (instanceID != 0 && instances.TryGetValue(instanceID, out Component com)) {
                return com;
            }
            return null;
        }

        /// <summary>
        /// 通过instanceID获得关联的Component
        /// </summary>
        public T Get<T>(int instanceID) where T : Component {
            Component com = GetComponent(instanceID);
            return com == null ? null : com as T;
        }

        /// <summary>
        /// 通过instanceID销毁关联的Component
        /// </summary>
        public void DestroyComponent(int instanceID) {
            if (instances.TryGetValue(instanceID, out Component com)) {
                instances.Remove(instanceID);
                if (com != null && com.gameObject != null) {
                    Object.Destroy(com.gameObject);
                }
            }
        }

        protected override JobHandle OnUpdate(JobHandle inputDeps) {
            // 如果实体被销毁，那么关联的component也要销毁
            Entities.WithoutBurst().ForEach((Entity entity, ref DynamicBuffer<ComponentInstance> componentInstanceBuffer) => {
                foreach (ComponentInstance componentInstance in componentInstanceBuffer) {
                    DestroyComponent(componentInstance.id);
                }
            }).Run();
            return inputDeps;
        }

    }

}
